package com.photoeditor.demo.ui.widget.face;

import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PointF;
import android.graphics.Rect;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;

import com.common.base.utils.DeviceUtils;
import com.photoeditor.R;
import com.photoeditor.demo.model.bean.face.CommonFaceBean;
import com.photoeditor.demo.model.bean.face.FacePoint;

import java.util.ArrayList;
import java.util.List;

/**
 * @author lyzirving
 * time        2018/12/14
 * email       lyzirving@sina.com
 * information
 */
public class FaceRectView extends View {

    public static final String TAG = FaceRectView.class.getSimpleName();


    private int mColor;
    private float mLineWidth;
    private int mViewWidth, mViewHeight;
    private boolean mCanDraw;
    private float mPointRadius;

    private Paint mPaint;
    private Rect mFace;
    private Path mPath;
    private List<Rect> mFaceList;
    private List<PointF> mPoints;

    public FaceRectView(Context context) {
        this(context, null);
    }

    public FaceRectView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public FaceRectView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAttrs(context, attrs);
        initField();
    }

    private void initField() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setColor(mColor);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeWidth(mLineWidth);
    }

    private void initAttrs(Context context, @Nullable AttributeSet attrs) {
        TypedArray ta = context.obtainStyledAttributes(R.styleable.FaceRectView);
        mColor = ta.getColor(R.styleable.FaceRectView_face_rect_color, Color.RED);
        mLineWidth = ta.getDimensionPixelSize(R.styleable.FaceRectView_face_rect_line_width, DeviceUtils.dip2px(0.5f));
        ta.recycle();
        setBackgroundColor(getResources().getColor(android.R.color.transparent));
        mPointRadius = DeviceUtils.dip2px(2);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mViewWidth = w;
        mViewHeight = h;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (!mCanDraw) return;

        if (mFace != null) {
            canvas.drawRect(mFace, mPaint);
        }
        if (mFaceList != null) {
            for (Rect r : mFaceList) {
                canvas.drawRect(r, mPaint);
            }
        }
        if (mPoints != null) {
            mPaint.setStyle(Paint.Style.STROKE);
            for (PointF f : mPoints) {
                canvas.drawCircle(f.x, f.y, mPointRadius, mPaint);
            }
        }
        if (mPath != null) {
            canvas.drawPath(mPath, mPaint);
        }
    }

    private void parseFacePointList(List<FacePoint> list, List<PointF> dst) {
        PointF p = null;
        FacePoint fp = null;
        for (int i = 0; i < list.size(); i++) {
            fp = list.get(i);
            p = new PointF(fp.x, fp.y);
            dst.add(p);
        }
    }

    public void setPath(Path path) {
        mPath = path;
        mCanDraw = true;
    }


    public void setFaceRect(Rect r) {
        mFace = new Rect(r);
        mCanDraw = true;
        invalidate();
    }

    public void setFaceListRect(List<Rect> list) {
        mFaceList = new ArrayList<>();
        for (Rect r : list) {
            mFaceList.add(new Rect(r));
        }
        mCanDraw = true;
        invalidate();
    }

    public void setCanDraw(boolean canDraw) {
        mCanDraw = canDraw;
        invalidate();
    }

    public boolean canDraw() {
        return mCanDraw;
    }

    public void parseCommonFaceBean(CommonFaceBean bean) {
        if (mPoints == null) mPoints = new ArrayList<>();
        mPoints.clear();
        parseFacePointList(bean.faceOval, mPoints);
        parseFacePointList(bean.leftEyeBrowTop, mPoints);
        parseFacePointList(bean.leftEyeBrowBottom, mPoints);
        parseFacePointList(bean.rightEyeBrowTop, mPoints);
        parseFacePointList(bean.rightEyeBrowBottom, mPoints);
        parseFacePointList(bean.leftEye, mPoints);
        parseFacePointList(bean.rightEye, mPoints);
        parseFacePointList(bean.upperLipTop, mPoints);
        parseFacePointList(bean.upperLipBottom, mPoints);
        parseFacePointList(bean.lowLipTop, mPoints);
        parseFacePointList(bean.lowLipBottom, mPoints);
        parseFacePointList(bean.noseBridge, mPoints);
        parseFacePointList(bean.noseBottom, mPoints);
        mCanDraw = true;
        invalidate();
    }

    private void parseFaceOvalExceptAdded(List<FacePoint> list, List<PointF> dst) {
        PointF p = null;
        FacePoint fp = null;
        for (int i = 0; i < list.size(); i++) {
            if (i <= 4 || i >= 32) continue;
            fp = list.get(i);
            p = new PointF(fp.x, fp.y);
            dst.add(p);
        }
    }

    public void parseCommonFaceBeanNoDraw(CommonFaceBean bean) {
        if (mPoints == null) mPoints = new ArrayList<>();
        mPoints.clear();
//        parseFacePointList(bean.faceOval, mPoints);
        parseFacePointList(bean.leftEyeBrowTop, mPoints);
        parseFacePointList(bean.leftEyeBrowBottom, mPoints);
        parseFacePointList(bean.rightEyeBrowTop, mPoints);
        parseFacePointList(bean.rightEyeBrowBottom, mPoints);
        parseFacePointList(bean.leftEye, mPoints);
        parseFacePointList(bean.rightEye, mPoints);
        parseFacePointList(bean.upperLipTop, mPoints);
        parseFacePointList(bean.upperLipBottom, mPoints);
        parseFacePointList(bean.lowLipTop, mPoints);
        parseFacePointList(bean.lowLipBottom, mPoints);
        parseFacePointList(bean.noseBridge, mPoints);
        parseFacePointList(bean.noseBottom, mPoints);
        parseFaceOvalExceptAdded(bean.faceOval, mPoints);

        //脸轮廓点
        float distRatioBetweenFaceAndEyeBrow = 0.4f;
        float diff = (bean.leftEyeBrowTop.get(4).y + bean.rightEyeBrowTop.get(4).y) / 2f - bean.faceOval.get(0).y;
        float realVal = (bean.leftEyeBrowTop.get(4).y + bean.rightEyeBrowTop.get(4).y) / 2f - diff * distRatioBetweenFaceAndEyeBrow;
        mPoints.add(new PointF(bean.faceOval.get(0).x, realVal));

        diff = bean.rightEyeBrowTop.get(4).y - bean.faceOval.get(1).y;
        realVal = bean.rightEyeBrowTop.get(4).y - diff * distRatioBetweenFaceAndEyeBrow;
        mPoints.add(new PointF(bean.faceOval.get(1).x, realVal));

        diff = bean.rightEyeBrowTop.get(3).y - bean.faceOval.get(2).y;
        realVal = bean.rightEyeBrowTop.get(3).y - diff * distRatioBetweenFaceAndEyeBrow;
        mPoints.add(new PointF(bean.faceOval.get(2).x, realVal));

        diff = bean.rightEyeBrowTop.get(2).y - bean.faceOval.get(3).y;
        realVal = bean.rightEyeBrowTop.get(2).y - diff * distRatioBetweenFaceAndEyeBrow;
        mPoints.add(new PointF(bean.faceOval.get(3).x, realVal));

        diff = bean.rightEyeBrowTop.get(1).y - bean.faceOval.get(4).y;
        realVal = bean.rightEyeBrowTop.get(1).y - diff * distRatioBetweenFaceAndEyeBrow;
        mPoints.add(new PointF(bean.faceOval.get(4).x, realVal));

        diff = bean.leftEyeBrowTop.get(1).y - bean.faceOval.get(32).y;
        realVal = bean.leftEyeBrowTop.get(1).y - diff * distRatioBetweenFaceAndEyeBrow;
        mPoints.add(new PointF(bean.faceOval.get(32).x, realVal));

        diff = bean.leftEyeBrowTop.get(2).y - bean.faceOval.get(33).y;
        realVal = bean.leftEyeBrowTop.get(2).y - diff * distRatioBetweenFaceAndEyeBrow;
        mPoints.add(new PointF(bean.faceOval.get(33).x, realVal));

        diff = bean.leftEyeBrowTop.get(3).y - bean.faceOval.get(34).y;
        realVal = bean.leftEyeBrowTop.get(3).y - diff * distRatioBetweenFaceAndEyeBrow;
        mPoints.add(new PointF(bean.faceOval.get(34).x, realVal));

        diff = bean.leftEyeBrowTop.get(4).y - bean.faceOval.get(35).y;
        realVal = bean.leftEyeBrowTop.get(4).y - diff * distRatioBetweenFaceAndEyeBrow;
        mPoints.add(new PointF(bean.faceOval.get(35).x, realVal));

        //发际线3个顶点
        float dist2Top = ((bean.leftEyeBrowTop.get(3).y + bean.rightEyeBrowTop.get(3).y) / 2 -
                (bean.faceOval.get(0).y + bean.faceOval.get(35).y) / 2) * 0.6f;
        //poxX: 脸轮廓的起、止点的中点，模拟发际线的x位置；
        float posX = (bean.faceOval.get(0).x + bean.faceOval.get(35).x) / 2;
        float posY = (bean.faceOval.get(0).y + bean.faceOval.get(35).y) / 2 - dist2Top;
        //发际线中部点，index: 70
        mPoints.add(new PointF(posX, posY));

        //发际线左右端点，index: 118(left)、50(right)
        posX = (bean.faceOval.get(33).x + bean.faceOval.get(34).x) / 2;
        posY = (bean.faceOval.get(33).y + bean.faceOval.get(34).y) / 2 - dist2Top;
        mPoints.add(new PointF(posX, posY));

        posX = (bean.faceOval.get(2).x + bean.faceOval.get(3).x) / 2;
        posY = (bean.faceOval.get(2).y + bean.faceOval.get(3).y) / 2 - dist2Top;
        mPoints.add(new PointF(posX, posY));

        //脖子顶点，共6个
        float neckHeight = (bean.faceOval.get(18).y - bean.lowLipBottom.get(4).y) * 0.8f;
        posX = (bean.faceOval.get(22).x + bean.faceOval.get(23).x) / 2;
        posY = (bean.faceOval.get(22).y + bean.faceOval.get(23).y) / 2 + neckHeight * 0.3f;
        mPoints.add(new PointF(posX, posY));
        ;//脖子左边点1

        posY = (bean.faceOval.get(22).y + bean.faceOval.get(23).y) / 2 + neckHeight * 1f;
        mPoints.add(new PointF(posX, posY));//脖子左边点2

        posX = bean.faceOval.get(18).x;
        posY = bean.faceOval.get(18).y + neckHeight * 0.2f;
        mPoints.add(new PointF(posX, posY));//脖子中部点1

        posY = bean.faceOval.get(18).y + neckHeight * 1f;
        mPoints.add(new PointF(posX, posY));//脖子中部点2

        posX = (bean.faceOval.get(13).x + bean.faceOval.get(14).x) / 2;
        posY = (bean.faceOval.get(13).y + bean.faceOval.get(14).y) / 2 + neckHeight * 0.2f;
        mPoints.add(new PointF(posX, posY));//脖子右边点1

        posY = (bean.faceOval.get(13).y + bean.faceOval.get(14).y) / 2 + neckHeight * 1f;
        mPoints.add(new PointF(posX, posY));//脖子右边点2
    }

    public void refresh(float left, float top, float right, float bottom) {
        if (mFace != null) {
            mFace.set((int) left, (int) top, (int) right, (int) bottom);
        }
        invalidate();
    }

    public void refresh(List<Rect> list) {
        if (mFaceList != null && mFaceList.size() > 0) {
            for (int i = 0; i < list.size(); i++) {
                mFaceList.set(i, new Rect(list.get(i)));
            }
        }
        invalidate();
    }

}
